package pers.cz.easyexcel.write;

import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFColor;
import pers.cz.common.annotation.Column;
import pers.cz.common.annotation.Table;
import pers.cz.common.meta.MetaHolder;
import pers.cz.common.meta.TableMeta;
import pers.cz.common.pub.AbstractEntity;
import pers.cz.common.pub.Condition;
import pers.cz.easyexcel.analysis.XlsxAnalysiser;
import pers.cz.easyexcel.meta.ColumnInfo;
import pers.cz.easyexcel.meta.RowInfo;
import pers.cz.easyexcel.meta.TitleInfo;
import pers.cz.easyexcel.style.DefaultCellStyle;
import pers.cz.easyexcel.tools.PoiUtils;
import utils.ObjUtils;
import utils.ReflectUtils;
import utils.UnsafeUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * @program: Jef-orm
 * @description: xlsx格式写入处理
 * @author: Cheng Zhi
 * @create: 2023-09-09 21:43
 **/
public class XlsxFileWriter implements FileWriter{

    /**
     * 表的元数据信息，包含表名以及字段映射值
     */
    private TableMeta tableMeta;

    private AbstractEntity entity;

    private Workbook workbook;

    public XlsxFileWriter(AbstractEntity entity, Workbook workbook) {
        this.tableMeta = MetaHolder.initTable(entity);
        this.entity = entity;
        this.workbook = workbook;
    }

    public void write(Boolean isUpdate) {
        Sheet sheet = getSheet();
        writeTitle(sheet);
        writeValue(sheet, isUpdate);
    }

    /**
     * 写入内容
     * @param sheet
     */
    private void writeValue(Sheet sheet, Boolean isUpdate) {

        if (isUpdate) {
            update(sheet, false);
        } else {
            insert(sheet);
        }
    }

    public void remove() {
        Sheet sheet = getSheet();
        writeTitle(sheet);
        update(sheet, true);
    }

    private void update(Sheet sheet, boolean isDelete) {
        // 先根据conditions确定坐标
        XlsxAnalysiser xlsxAnalysiser = new XlsxAnalysiser(entity, workbook);
        Row row = sheet.getRow(0);
        List<TitleInfo> sheetTitle = xlsxAnalysiser.getSheetTitle(row);
        int lastRowNum = sheet.getLastRowNum();
        List<Integer> deleteLineNumbers = new LinkedList<Integer>();
        for (int i=1; i<=lastRowNum; i++) {
            // 2、解析内容
            List<ColumnInfo> sheetColumnInfo = xlsxAnalysiser.getSheetColumnInfo(sheet.getRow(i), sheetTitle);

            // 3、组装为对象
            if (sheetColumnInfo != null && sheetColumnInfo.size() > 0) {
                if (isDelete) {
                    // 删除了之后上移,上移之后lastRowNum会改变
                    int rowNumber = sheetColumnInfo.get(0).getRowNumber();
                    sheet.removeRow(sheet.getRow(rowNumber));
                    deleteLineNumbers.add(rowNumber);
                    // n 负数表示上移，正数表示下移
                    //sheet.shiftRows(sheetColumnInfo.get(0).getRowNumber()+1, lastRowNum, -1);
                    continue;
                }

                Field[] fields = entity.getClass().getDeclaredFields();

                for (Field field : fields) {
                    Object value = UnsafeUtils.forcedGetValue(entity, field);
                    if (value != null && !value.equals(0)) {
                        String fieldName = field.getName();

                        // 根据字段值，再找到列号
                        for (TitleInfo titleInfo : sheetTitle) {
                            if (titleInfo.getFieldName().equals(fieldName)) {
                                int number = titleInfo.getNumber(); // 真正需要改的列号

                                Cell cell = sheet.getRow(sheetColumnInfo.get(0).getRowNumber()).getCell(number);
                                PoiUtils.writeCell(cell, UnsafeUtils.forcedGetValue(entity, field));
                            }
                        }
                    }
                }
            }
        }

        dealUpShift(sheet, deleteLineNumbers);
    }

    /**
     * 上移单元格
     * @param sheet
     * @param deleteLineNumbers
     */
    private void dealUpShift(Sheet sheet, List<Integer> deleteLineNumbers) {
        int lastRowNum = sheet.getLastRowNum();
        if (deleteLineNumbers.size() > 0) {
            // 链表反转
            arrayReverse(deleteLineNumbers);
            for (int lineNumber : deleteLineNumbers) {
                // 删除行后每行上移一个单位
                sheet.shiftRows(lineNumber + 1, lastRowNum, -1);
            }

        }
    }

    /**
     * 链表反转
     * @param sourceList
     */
    private void arrayReverse(List<Integer> sourceList) {

        int i,t;
        int size = sourceList.size();
        for (i =0; i<size/2; i++) {
            t = sourceList.get(i);
            sourceList.set(i, sourceList.get(size - i -1));
            sourceList.set(size-i-1, t);
        }
    }

    private void insert(Sheet sheet) {
        // 从sheet页中追加内容,从最后一个有效行开始写入
        int lastRowNum = sheet.getLastRowNum();
        Field[] declaredFields = entity.getClass().getDeclaredFields();
        Row row = sheet.createRow(++lastRowNum);
        int i = 0;
        for (Field field : declaredFields) {
            Cell cell = row.createCell(i);
            PoiUtils.writeCell(cell, UnsafeUtils.forcedGetValue(entity, field));
            i ++;
        }
    }

    /**
     * 写入标题行
     * @param sheet
     */
    private void writeTitle(Sheet sheet) {

        // 如果sheet页存在内容，则认为是追加操作，不去重新写入标题
        if (sheet.getLastRowNum() > 0) {
            return;
        }
        Row row = sheet.createRow(0);

        int i = 0;
        for (TitleInfo titleInfo : getTitles()) {

            Cell cell = row.createCell(i);
            cell.setCellValue(titleInfo.getTitleName());
            cell.setCellStyle(titleInfo.getCellStyle());
            i ++;
        }
    }


    private List<TitleInfo> getTitles() {

        Map<String, Column> columnMap = getColums();
        List<TitleInfo> titleInfos = new LinkedList<>();

        for (String title : columnMap.keySet()) {
            TitleInfo titleInfo = new TitleInfo();
            titleInfo.setTitleName(columnMap.get(title).excelColumn());
            // 创建单元格样式
            XSSFCellStyle cellStyle = (XSSFCellStyle) workbook.createCellStyle();
            cellStyle.setAlignment(HorizontalAlignment.CENTER);
            cellStyle.setFillForegroundColor((short)9);
            titleInfo.setCellStyle(cellStyle);
            titleInfos.add(titleInfo);
        }

        return titleInfos;
    }

    private Sheet getSheet() {

        // 写文件的时候一般不会出现一个实体对象的内容写到不同sheet页的场景
        String sheetName = getTable().sheetName();
        Sheet sheet = workbook.getSheet(sheetName);

        if (sheet != null) {
            return sheet;
        }
        return workbook.createSheet(sheetName);
    }

    @Override
    public Table getTable() {
        return tableMeta.getTable();
    }

    @Override
    public Map<String, Column> getColums() {
        return tableMeta.getColumns();
    }
}
